// <copyright file="MelodicChange.cs" company="Largo">
// Copyright (c) 2009 All Right Reserved
// </copyright>
// <author> vl </author>
// <email></email>
// <date>2009-01-01</date>
// <summary>Contains ...</summary>

namespace LargoBase.Motives
{
    using LargoBase.Abstract;
    using LargoBase.Enums;
    using LargoBase.Localization;
    using System.Diagnostics.Contracts;
    using System.Globalization;
    using System.Text;
    using System.Xml.Linq;

    /// <summary>
    /// Melodic Change.
    /// </summary>
    public sealed class MelodicChange : AbstractChange {
        #region Fields
        /// <summary> Melodic motive. </summary>
        private MelodicMotive melodicMotive;
        #endregion

        #region Constructors
        /// <summary>
        /// Initializes a new instance of the <see cref="MelodicChange"/> class.
        /// </summary>
        [UsedImplicitly]
        public MelodicChange() {
        }

        /// <summary>
        /// Initializes a new instance of the <see cref="MelodicChange"/> class.
        /// </summary>
        /// <param name="xchange">The given change.</param>
        public MelodicChange(XElement xchange)
            : base(xchange) {
                Contract.Requires(xchange != null);
           //// if (xchange == null) { return; }

           this.MelodicFunction = DataEnums.ReadAttributeMelodicFunction(xchange.Attribute("MelodicFunction"));
           this.MelodicShape = DataEnums.ReadAttributeMelodicShape(xchange.Attribute("MelodicShape"));
           ////201509!!!!! this.MelodicFunction = (MelodicFunction)LibSupport.ReadByteAttribute(xchange.Attribute("MelodicFunction"));
           //// this.MelodicFunction = LargoBase.Enums.MelodicFunction.HarmonicFilling;
           ////201509!!!!! this.MelodicShape = (MelodicShape)LibSupport.ReadByteAttribute(xchange.Attribute("MelodicShape"));
           //// this.MelodicShape = LargoBase.Enums.MelodicShape.Original; 
           this.MotiveNumber = XmlSupport.ReadIntegerAttribute(xchange.Attribute("MotiveNumber"));
           this.MusicalLineType = MusicalLineType.Melodic;
           this.ChangeType = MusicalChangeType.Melodic;
        }

        /// <summary>
        /// Initializes a new instance of the <see cref="MelodicChange"/> class.
        /// </summary>
        /// <param name="givenBar">The given bar.</param>
        /// <param name="givenLine">The given line.</param>
        /// <param name="givenFunction">The given function.</param>
        public MelodicChange(int givenBar, int givenLine, MelodicFunction givenFunction)
            : base(givenBar, givenLine, MusicalChangeType.Melodic) {
            this.MusicalLineType = MusicalLineType.Melodic;
            this.MelodicFunction = givenFunction;
        }

        /// <summary>
        /// Initializes a new instance of the <see cref="MelodicChange"/> class.
        /// </summary>
        /// <param name="givenBar">The given bar.</param>
        /// <param name="givenLine">The given line.</param>
        public MelodicChange(int givenBar, int givenLine)
            : base(givenBar, givenLine, MusicalChangeType.Melodic) {
                this.MusicalLineType = MusicalLineType.Melodic;
        }
        
        #endregion

        #region Properties - Xml
        /// <summary>
        /// Gets Xml representation.
        /// </summary>
        /// <value>
        /// Property description.
        /// </value>
        public override XElement GetXElement {
            get {
                var change = base.GetXElement;
                change.Add(new XAttribute("MelodicFunction", this.MelodicFunction));
                change.Add(new XAttribute("MelodicShape", this.MelodicShape));
                change.Add(new XAttribute("MotiveNumber", this.MotiveNumber ?? 0));
                change.Add(new XAttribute("IsStop", this.IsStop));
                return change;
            }
        }
        #endregion

        #region Properties
        /// <summary> Gets or sets class of melodic part. </summary>
        /// <value> Property description. </value>
        public MelodicFunction MelodicFunction { get; set; }

        /// <summary>
        /// Gets or sets the melodic shape.
        /// </summary>
        /// <value>
        /// The melodic shape.
        /// </value>
        public MelodicShape MelodicShape { get; set; }

        /// <summary> Gets or sets class of melodic part. </summary>
        /// <value> Property description. </value>
        public int? MotiveNumber { get; set; }

        /// <summary>
        /// Gets or sets the line letter.
        /// </summary>
        /// <value>
        /// The line letter.
        /// </value>
        public int? LineLetter { get; set; }

        /// <summary>
        /// Gets or sets the motivic change.
        /// </summary>
        /// <value>
        /// The motivic change.
        /// </value>
        public MotivicChangeType MotivicChange { get; set; }

        /// <summary>
        /// Gets or sets MelodicMotive.
        /// </summary>
        /// <value> General musical property.</value> 
        public MelodicMotive MelodicMotive {
            get {
                if (this.MotiveNumber == null) {
                    return null;
                }

                var isPrepared = this.melodicMotive != null;
                if (isPrepared) {
                    return this.melodicMotive;
                }
                ////core bool isPrepared = (this.melodicMotive != null) && this.melodicMotive.Number == this.MotiveNumber && this.melodicMotive.CoreId == this.BlockModel.MelodicCore.Id;
                ////core if (isPrepared) { return this.melodicMotive; }

                //// if (this.BlockModel != null) {
                ////     this.melodicMotive = this.BlockModel.Core.MelodicCore.GetMelodicMotive((int)this.MotiveNumber);
                //// }

                return this.melodicMotive;
            }

            set => this.melodicMotive = value;
        }

        #endregion

        #region String properties
        /// <summary>
        /// Gets MelodicTypeString.
        /// </summary>
        /// <value> Property description. </value>
        [UsedImplicitly]
        public string MelodicTypeString => LocalizedMusic.String("MelodicFunction" + ((byte)this.MelodicFunction).ToString(CultureInfo.CurrentCulture));

        #endregion

        #region Static factory methods
        /// <summary>
        /// Gets the new end rhythmic change.
        /// </summary>
        /// <param name="barNumber">The bar number.</param>
        /// <param name="lineIndex">Index of the line.</param>
        /// <returns>
        /// Returns object.
        /// </returns>
        public static MelodicChange GetNewMelodicStopChange(int barNumber, byte lineIndex) {
            Contract.Ensures(Contract.Result<MelodicChange>() != null);

            var change = new MelodicChange(barNumber, lineIndex) { MotivicChange = MotivicChangeType.MainMotiveStop };
            return change;
        }
        #endregion

        #region Public methods
        /// <summary>
        /// Clones this instance.
        /// </summary>
        /// <returns> Returns object. </returns>
        public override object Clone() {
            var tmc = new MelodicChange(this.BarNumber, this.LineIndex) {
                    MotiveNumber = this.MotiveNumber, MelodicFunction = this.MelodicFunction
            };
            //// tmc.BlockModel = this.BlockModel;

            return tmc;
        }
        #endregion

        #region String representation

        /// <summary> String representation of the object. </summary>
        /// <returns> Returns value. </returns>
        public override string ToString() {
            var s = new StringBuilder();
            s.AppendFormat(CultureInfo.CurrentCulture, base.ToString());
            s.Append("," + this.LineTypeString);
            s.Append(", Motive " + this.MotiveNumber);
            return s.ToString();
        }
        #endregion
    }
}